/*!
 * \file conntrack.h
 *
 * \brief conntrack(ct)相关结构体定义
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 * 连接跟踪信息
 * 
 * \version 2.0
 * \author yaolhl
 * \date 2014/09/29
 *
 */


#ifndef __CONNTRACK_H_
#define __CONNTRACK_H_

#include <pthread.h>
#include <arpa/inet.h>
//#include <uuid.h>
//#include <asm/atomic.h>
#include <event2/event.h>
#include <event2/event_struct.h>

#include "frcomm.h"
#include "frlist.h"
#include "frstr.h"
#include "frsutl.h"
#include "frtimer.h"

#include "module_comm.h"

#define APM_SESSION_START    1  /* session开始 */
#define APM_SESSION_STOP     2  /* session结束 */

#define APM_L7PROTO_STATUS_UNKNOWN      0  /* L7层协议判断未知 */
#define APM_L7PROTO_STATUS_IN_PROGRESS  1  /* L7层协议判断进行中 */
#define APM_L7PROTO_STATUS_FAIL         2  /* L7层协议判断失败 */
#define APM_L7PROTO_STATUS_DONE         3  /* L7层协议判断完成 */

//#define APM_L7_IN_PROGRESS 0   /* 正在分析中 */
//#define APM_L7_REQ_DONE    1   /* request分析已经完成  */
//#define APM_L7_DONE        2   /* response分析已经完成  */

#define APM_CONNTRACK_SESSION_UNLOCKED  0  /* i_sesion_locked标志位为0 */
#define APM_CONNTRACK_SESSION_LOCKED    1

/* ct 连接状态 */
#define APM_CONNECT_UNKNOWN         0
#define APM_CONNECT_SYN_SENT        1
#define APM_CONNECT_SYN_RECV        2
#define APM_CONNECT_ESTABLISHED     3
#define APM_CONNECT_CLOSED          4
#define APM_CONNECT_TIMEOUT         5

/* 模块识别状态 */
#define APM_MODULE_STATUS_UNKNOWN       0   /* 未知 */
#define APM_MODULE_STATUS_AUOTODETECT   1   /* 自动识别的模块 */
#define APM_MODULE_STATUS_DEFINE        2   /* 用户指定的模块 */

#define APM_CT_DETECT_HASH_SIZE     256

struct __st_conntrack;

/*
*  按L7层协议解码后数据
*/
//typedef enum Lua_datatype {
//    NUMBER = 1,
//    STRING
//} Lua_datatype;
//#define LUA_NUMBER  1
//#define LUA_

/* Lua解析后数据 */
//typedef struct __st_L7_luadata {
//    char* p_field_name; /* 字段名 */
//
//    enum Lua_datatype  datatype; /* 数据类型，支持两种 number和string */
//    void* p_field_data; /* 数据值 */
//    unsigned int ui_datalen; /* 数值大小 */
//} L7_luadata;

/*!
*   @brief 记录用户登录信息，例如：\n
*    1. ORACLE用户登录后，应生成L7_SESSION数据，SID等相关信息记录在p_session_private指向的结构体中\n
*    2. 对于HTTP协议，用户登录后应SESSION数据
*/
typedef struct __st_l7_session {
    char arr_session_id[APM_UUID_SIZE];  /*!< 内部使用的session id，用户向实时数据分析平台发送数据时用，jsession_id等应存放在session_private中 */

    /* session数据 */
    char *p_username; /*!< 用户登录的用户名 */
    struct timeval st_session_starttime;/*!< 用户登录时间 */
    struct timeval st_session_stoptime; /*!< 用户退出时间 */

    void *p_session_private; /*!< 除用户名外，不同应用个性化信息（例如ORACLE登录时的客户端名称、版本号、SID等）保存在这里 */
    //int (**pp_session_format)(void *p_session_private); /* session format函数，用于格式化session_private数据，从module定义中复制过来 */
    //int (**pp_session_destory)(void *p_session_private);/* session destory函数，用于释放session_private数据，从module定义中复制过来 */

    int i_status; /*!< 状态，APM_SESSION_START表示开始一个session， APM_SESSION_STOP表示该session已经终止 */
} L7_session;

/*!
* @brief 协议分析数据\n
*   考虑到协议嵌套的情况，我们把每种协议分析结果存入L7_data_list链表\n
*   当request请求分析完成后（所有嵌套协议完成后），status标志位应设置为APM_L7_REQ_DONE，并向实时数据平台发送数据\n
*   同理，response请求分析完成后，status应设置为APM_L7_DONE，并向实时数据平台发送数据\n
*   \n
*   当response数据完成向实时数据平台的发送后，L7数据应被立即释放\n
*   当连接timeout后，L7数据也应被释放
*
*/

typedef struct __st_L7_analyzer {
    L7_module *p_st_l7_module;          /*!< 协议解析模块(没有协议号时NULL) 注意:释放该模块时,减少引用次数 */
    
    //int (**pp_l7_analyze)(struct __st_conntrack *p_st_conn, Analyz_data_in *p_st_data_in, Analyz_data_out *p_st_data_out); /* 用于L7层数据解码 */

    /* L7层分析结果 */
    L7_session      *p_st_session;      /*!< 当前L7的session */
    L7_transaction  *p_st_transaction;  /*!< 当前分析的交易 */

} L7_analyzer;


/*! @brief 数据解密相关定义 */
typedef enum __em_decrpt_type
{
    FRDECRPT_UNKNOWN=0,
    FRDECRPT_SSL = 1,           /*!< ssl解密 */
}Frdecrpt_type;

//typedef struct __st_decrpt_ssl {
//    char   *p_file;                 //证书文件名
//    char   *p_password;             //证书密码
//} Frdecrpt_ssl;

/*! @brief 数据包相关信息 */
typedef struct __st_cap_info {
    u_short ip_proto;
    int i_direction;                /*!< 当前数据方向 */
    u_int src_ip, dst_ip;           /*!< 实际数据包的ip,并不是ct上固定的ip */
    u_short src_port, dst_port;     /*!< 实际数据包的port,并不是ct上固定的port */
    struct timeval st_timestamp;    /*!< 数据包发生时间 */

    Franalyz_cmd em_analyz_cmd;     /*!< FRANALYZ_CMD_SYN FRANALYZ_CMD_FIN FRANALYZ_CMD_DATA */
} FrcapInfo;

/*! @brief 解码相关信息 */
typedef struct __st_decrpt_info {
    unsigned long ul_version;
    Frdecrpt_type em_decrpt_type;   /*!< 预留 */
    void *p_st_decrpt;              /*!< em_decrpt_type == FRDECRPT_SSL时,p_st_decrpt为DSSL_Session* */
    FrcapInfo st_capinfo;
} FrdecrptInfo;

/*! @brief lua自定义脚本 */
typedef struct __st_lua_info {
    void   *p_lua_cfg;          /*!< Lua_cfg * */
    unsigned long ul_lua_version;
} FrluaInfo;

/*! @brief 父连接信息 */
typedef struct __st_master_info {
    u_int   src_ip;         /*!< 父连接信息 */
    u_short src_port;       /*!< 父连接信息 */
    u_int   dst_ip;         /*!< 父连接信息 */
    u_short dst_port;       /*!< 父连接信息 */

    L7_module *p_st_l7_module;
    Frlist_header *p_lst_hdr_param;

    u_int   exp_src_ip;     /*!< 进行关联时使用的信息 */
    u_short exp_src_port;   /*!< 进行关联时使用的信息 */
    u_int   exp_dst_ip;     /*!< 进行关联时使用的信息 */
    u_short exp_dst_port;   /*!< 进行关联时使用的信息 */

} FrmasterInfo;

/*! @brief 连接跟踪 */
typedef struct __st_conntrack {
    char arr_connection_id[APM_UUID_SIZE];  /*!< 内部使用的connection id，用户向实时数据分析平台发送数据时用 */
    pthread_spinlock_t lock; /*!< 自旋锁 */

    unsigned int refcnt;                /*!< 引用次数(原子操作)，引用次数<=0时才能释放 */

    uint32_t  flg_update:1,             /*!< 有数据包:FR_YES, 否则:FR_NO */
              flg_status:7,             /*!< 连接状态： APM_CONNECT_SYN_SENT/APM_CONNECT_SYN_RECV
                                                    APM_CONNECT_ESTABLISHED/APM_CONNECT_CLOSED/APM_CONNECT_TIMEOUT */
              flg_inTask:1,             /*!< FR_YES:增加到taskskb_mng,FR_NO:没有增加到taskskb_mng */
              flg_direct_known:1,       /*!< FR_DIRECT_UNKNOWN FR_DIRECT_KNOWN */
              flg_chg_direct:1,         /*!< 更改ct方向  FR_NO:没有改变; FR_YES:更改ct方向 */
              flg_report_conn_info:1,   /*!< 连接上报标识  FR_YES:已上报 FR_NO:未上报 */
              flg_report_conn_dead:1,   /*!< 僵尸连接上报标识  FR_YES:已上报 FR_NO:未上报*/
              flg_has_master:1,         /*!< 关联连接有父连接标识 FR_YES:有 FR_NO:无  */
              flg_chg_stat_ip:2,        /*!< 更改上报统计ip和端口 0:无;1:有;2:刚发生变化 */

              flg_cap_peek_end:1,       /*!< 数据包管理flag; FR_YES:不再进行peek操作 */
              flg_cap_redo:1,           /*!< 数据包管理flag; FR_YES:数据包重做;否则不保留数据包 (预留,暂时没使用) */

              flg_task_out:1,           /*!< 0:不退出该ct解码,1:退出该ct解码 */
              flg_drop_pcap:1,          /*!< 0:系统丢弃该数据包,1:主框架主动丢弃该数据包,不进入解码模块,会造成流量统计变小 */
              flg_reserve:12;

    struct timeval st_connection_created;      /*!< 连接创建时间 */
    struct timeval st_connection_established;  /*!< 连接成功时间，TCP为三次握手后时间，UDP=connection_created */
    struct timeval st_connection_lastskb_time; /*!< 最后收发数据包时间 */
    struct timeval st_connection_close_time;   /*!< 数据包close时间(fin/reset) */

    /* Timer function; drops refcnt when it goes off. */
    /* UDP timer?? */
    Timer_entry *p_st_timer_entry;

    /* 基本信息
     * 这里假定客户端发起,服务端的信息保存到dest里。
     * 不考虑服务端主动连接的情况,这种情况时,把服务器的信息还是保存到dest里 */
    u_short ip_proto;             /*!< 6(IPPROTO_TCP) / 17(IPPROTO_UDP) */
    char src_mac[APM_MAC_SIZE];   /*!< src mac */
    char dst_mac[APM_MAC_SIZE];   /*!< dst mac */
    u_int   src_ip;
    u_short src_port;
    u_int   dst_ip;
    u_short dst_port;

    FrmasterInfo st_masterInfo;  /*!< 关联连接的父连接 */

    /* 统计用src port, dest port
     *
     * flg_chg_stat_ip!=0 程序主动更改统计端口
     * flg_has_master==FR_YES 为FrmasterInfo.src_port FrmasterInfo.dst_port
     * 否则不使用该端口  */
    u_short stat_src_port;
    u_short stat_dst_port;

    /* 连接数上报时使用的ip信息 */
    u_int   report_src_ip;
    u_int   report_dst_ip;
    u_short report_dst_port;

    /* 数据包管理 */
    Frlist_header lst_cap_queue;    /*!< 数据包缓存队列,FIFO */
    unsigned int ui_cap_peek_num;   /*!< 数据peek位置 0:没有peek过 */
    unsigned int ui_done_data_cnt;  /*!< 已处理数据包个数 */
    unsigned int ui_detect_data_cnt[2];/*!< 已经判断协议的数据包个数  idx=0:FR_DIRECT_CLIENT2SRV; idx=1:FR_DIRECT_SRV2CLIENT */

    int i_flag_module_status;         /*!< APM_MODULE_STATUS_UNKNOWN/APM_MODULE_STATUS_AUOTODETECT/APM_MODULE_STATUS_DEFINE */
    unsigned int ui_define_ver;       /*!< 用户指定协议时有效,Frproto_mng->ui_ver */

    /* 加密管理 */
    FrdecrptInfo st_decrptInfo;       /*!< 数据解密 */


    L7_analyzer st_l7_analyzer;       /*!< 获取时使用ct->lock */
    int i_flag_l7proto_status;        /*!< 协议分析状态: APM_L7PROTO_STATUS_UNKNOWN, APM_L7PROTO_STATUS_IN_PROGRESS
                                         , APM_L7PROTO_STATUS_FAIL, APM_L7PROTO_STATUS_DONE */
    FrluaInfo st_luaInfo;             /*!< lua 信息,对上报数据用lua进行再次操作 */

    L4_transaction st_l4_transaction;

    Frhash_header *p_st_hash_detect_data;

    /* 包数据统计信息 */
    unsigned long ul_rx_packets;
    unsigned long ul_tx_packets;
    unsigned long ul_drop_packets;

    unsigned long ul_rx_bytes;
    unsigned long ul_tx_bytes;

    unsigned long ul_seq;               /*!< 序列号 */

} Conntrack;

#endif
